
#include <QXmlStreamReader>
#include <QFile>
#include <QDebug>

#include "SymbolXmlSerializer.h"
#include "SymbolModel.h"

SymbolXmlSerializer::SymbolXmlSerializer():
    CurrentNewIndex( 0 )
{

}

SymbolXmlSerializer::~SymbolXmlSerializer()
{

}

bool SymbolXmlSerializer::saveFile( const QString & filename, const SymbolModel * model )
{
    QFile
        file( filename );
        
    if( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
    {
        return false;
    }
    
    streamWriter = new QXmlStreamWriter( &file );
    streamWriter->setAutoFormatting( true );
    
    streamWriter->writeStartDocument();
    streamWriter->writeStartElement( "Symbols" );
    
    foreach( const Symbol & symbol, model->getSymbolTable() )
    {
        streamWriter->writeStartElement( "Symbol" );
        streamWriter->writeAttribute( "Index" , QString::number( symbol.index ) );
        streamWriter->writeAttribute( "ItIsUsed" , symbol.isUsed ? "true" : "false" );
        streamWriter->writeTextElement( "Name", symbol.name );
        
        if( !symbol.comments.isEmpty() )
        {
            streamWriter->writeTextElement( "Comments", symbol.comments );
        }
        
        streamWriter->writeEndElement();
    }
    
    streamWriter->writeEndElement();
    streamWriter->writeEndDocument();
    delete streamWriter;

    return true;
}

bool SymbolXmlSerializer::loadFile( const QString & filename, SymbolModel * model )
{
    QFile
        file( filename );
        
    if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
    {
        return false;
    }
    
    streamReader = new QXmlStreamReader( &file );
    
    while (!streamReader->atEnd() )
    {
        switch( streamReader->readNext() )
        {
            case QXmlStreamReader::StartDocument:
                break;
            
            case QXmlStreamReader::StartElement:
            {
                if( streamReader->name() == "Symbols" )
                {
                    handleSymbols();
                }
                else
                {
                    //TODO throw exception
                }

            }
            break;
                
            case QXmlStreamReader::Characters:
            {
                Q_ASSERT( streamReader->isWhitespace() );
            }
            break;
                
            case QXmlStreamReader::EndDocument:
                break;

            default:
                qDebug() << "Unexpected element " << streamReader->tokenString() << "\n";
                delete streamReader;
                return false;
        }
    }
    
    if ( streamReader->hasError() ) 
    {
        qDebug() << "Error in xml : " << streamReader->errorString();
        delete streamReader;
        return false;
    }

    CurrentNewIndex++;
    model->initializeModel( CurrentNewIndex, SymbolTable );

    delete streamReader;
    return true;
}

void SymbolXmlSerializer::handleSymbols()
{
    QXmlStreamReader::TokenType tokenType = streamReader->readNext();
    
    while ( tokenType != QXmlStreamReader::EndElement )
    {
        switch( tokenType )
        {
            case QXmlStreamReader::StartElement:
            {
                if( streamReader->name() == "Symbol" )
                {
                    handleSymbol();
                }
                else
                {
                    qDebug() << "Unsupported tag " << streamReader->name() << " in Label tag\n";
                }

                break;
            }
            
            case QXmlStreamReader::Characters:
            {
                Q_ASSERT( streamReader->isWhitespace() );
            }
            break;

            default:
                qDebug() << "Unexpected element " << streamReader->tokenType() << "\n";
                return;
        }
        
        tokenType = streamReader->readNext();
    }
}

void SymbolXmlSerializer::handleSymbol()
{
    QXmlStreamAttributes 
        attributes = streamReader->attributes();
    QString
        index_string;
    bool
        index_is_integer;
    int
        index;
    QXmlStreamReader::TokenType
        tokenType;
    Symbol
        symbol;
        
    if( attributes.hasAttribute( "Index" ) )
    {

        index_string = attributes.value( "Index" ).toString();
        index = index_string.toInt( &index_is_integer );
        
        if ( CurrentNewIndex < index )
        {
            CurrentNewIndex = index;
        }

        if( !index_is_integer )
        {
            //:TODO:
            qDebug() << "index is not an integer but is \"" << index_string << "\"";
            return;
        }
    }
    
    symbol.isUsed = true;
    symbol.index = index;
    
    tokenType = streamReader->readNext();
    
    while ( tokenType != QXmlStreamReader::EndElement )
    {
        switch( tokenType )
        {
            case QXmlStreamReader::StartElement:
            {
                if( streamReader->name() == "Comments" )
                {
                    symbol.comments = readLeafNode();
                }
                else if( streamReader->name() == "Name" )
                {
                    symbol.name = readLeafNode();
                }
                else
                {
                    qDebug() << "unsupported tags " << streamReader->name() << " in element Localization";
                }

                break;
            }
            
            case QXmlStreamReader::Characters:
            {
                Q_ASSERT( streamReader->isWhitespace() );
            }
            break;

            default:
                qDebug() << "Unexpected element " << streamReader->tokenType() << "\n";
                return;
        }
        
        tokenType = streamReader->readNext();
    }
    
    SymbolTable.push_back( symbol );
    
}

QString SymbolXmlSerializer::readLeafNode()
{
    QString
        result;
    QXmlStreamReader::TokenType
        tokenType;
        
    tokenType = streamReader->readNext();
    
    while ( tokenType != QXmlStreamReader::EndElement )
    {
        if( tokenType == QXmlStreamReader::Characters )
        {
            result += streamReader->text();
        }
        else
        {
            qDebug() << "Unexpected element " << streamReader->tokenType() << "\n";
            return "";
        }
        
        tokenType = streamReader->readNext();
    }
    
    return result;
}